//Linux C plus plus file
/************************************************************************
*
*
*       			FileName:mempool.cpp
*
*         			Author.wzj
*
*       			Email:345517039@qq.com
*
*      	    		Create:2017-06-22 23:42:57
*
*      		    	Description:-
*
*
*************************************************************************/
#include "mempool.h"

#define MEM_ALIGN  16

/**
 * @brief 
 */
MemPool::MemPool(){
	this->ctx.allocated = 0;
	this->ctx.head = this->ctx.tail= NULL;
	this->ctx.level = 0;
	this->ctx.count =0;
	this->ctx.queue.count = 0;
	this->ctx.queue.queueHead = ctx.queue.queueTail = NULL;
	this->ctx.freeMem.clear();
	this->ctx.largeMem.clear();
}



/**
 * @brief 
 */
MemPool::~MemPool(){
	//管理头部标签的;
	struct Node_t *temp = NULL;
	if(ctx.queue.count > 0){
		temp = ctx.queue.queueHead;
		while( temp != ctx.queue.queueTail){
			ctx.queue.queueHead = ctx.queue.queueHead->next;
			free(temp);
			temp = ctx.queue.queueHead;
		}
	}
	//析构函数;
	if ( ctx.head != NULL){
		struct mempool_elem * ptemp = ctx.head;
		struct mempool_elem * ptext = NULL;
		while(ptemp){
			ptext = ptemp->next;
			free(ptemp);
			ptemp = NULL;
			ptemp = ptext;
		}
		ctx.head = ctx.tail = NULL;
	}
	//管理大内存块的hashmap;
	if(ctx.largeMem.size() >0){
		for(__gnu_cxx::hash_map<int, struct Node_t *>::const_iterator it = ctx.largeMem.begin(); it != ctx.largeMem.end(); ++it){
			if(it->second){
				//宏函数释放吧;
			}
		}
	}
	//空闲内存块的hashmap;
	if(ctx.freeMem.size() > 0){
		for(__gnu_cxx::hash_map<int, struct Node_t *>::const_iterator it = ctx.freeMem.begin(); it != ctx.freeMem.end(); ++it){
			if(it->second){
				//宏函数释放吧;
			}
		}
	}
}



/**
 * @brief 内存池初始化;
 *
 * @param level 内存池级别;
 *
 * @return 
 */
int MemPool::init(int level){
	int iRet = RET::FAIL;
	char *_temp = new char[sysTemMemPageSize];
	if ( !_temp ){
		fprintf(stderr, "[ ERROR ]ALLOC MEM OPERATION FAILURE IN FUNCTION:%s LINE:%d\n", __func__, __LINE__);
		return iRet;
	}
	struct mempool_elem * temp = (struct mempool_elem *)_temp;
	temp->isFull=false;
	temp->startaddr =(char *)((char *)temp + MEM_ELEM_HEAD_LEN);
	temp->curraddr = temp->startaddr;
	temp->pageSize = sysTemMemPageSize;
	temp->usedSize = sysTemMemPageSize - MEM_ELEM_HEAD_LEN;	
	temp->next=temp->prev = NULL;
	
	this->ctx.head = this->ctx.tail = temp;
	this->ctx.allocated += sysTemMemPageSize;
	this->ctx.level = level;
	this->ctx.count++;
	return RET::SUCCESS;
}


/**
 * @brief:
 * @author:
 * @para:  int size 
 * @return value:
 */
void * MemPool::allocateMemFromMempool(int size){
	void *addr = NULL;
	struct Node_t *node;
	if(size <=  0){
		DEBUG_TRACE(2,("[ ERROR ]GET MEM SIZE:%d IS NOT AVALIABLE IN FUNCTION:%s LINE:%d\n", size, __func__, __LINE__));
		return NULL;
	}
	size = (size + (MEM_ALIGN - 1))&(~(MEM_ALIGN - 1));
	//先判断size是不是小于4K;
	if(size <= sysTemMemPageSize){
		//先从hashTable里遍历;
		if( this->ctx.freeMem.size()!=0 && this->ctx.freeMem[size]){
			node = ctx.freeMem[size];
			ctx.freeMem[size] = node->next;
			addr = node->addr;
			INIT_NODE(node);
			if ( ctx.queue.queueHead == NULL ){
				ctx.queue.queueHead = ctx.queue.queueTail = node;
			}else{
				ctx.queue.queueTail->next = node;
				ctx.queue.queueTail = node;
			}
			ctx.queue.count++;
			return addr;
		}
		//先从内存块申请;
		struct mempool_elem *p = this->ctx.head;
		while(p&&!p->isFull){
			if(p->usedSize > size){
				void *addr = p->curraddr;
				p->curraddr += size;
				p->usedSize -= size;
				return addr;
			}else if(size_t(p->curraddr - p->startaddr) == sysTemMemPageSize - MEM_ELEM_HEAD_LEN){ //当前的地址-内存块的首地址 =
				p->isFull=true;
			}
			p = p->next;
		}
		//内存块不够了就申请吧;
		char * _tmp = new char[sysTemMemPageSize];
		struct mempool_elem *tmp = (struct mempool_elem *)_tmp;
		tmp->isFull = false;
		tmp->index = ++this->ctx.count;
		tmp->startaddr =(char *)tmp+MEM_ELEM_HEAD_LEN;
		tmp->curraddr = tmp->startaddr;
		tmp->usedSize = sysTemMemPageSize - MEM_ELEM_HEAD_LEN;
		tmp->next = NULL;
		if(!this->ctx.head){
			this->ctx.head = this->ctx.tail = tmp;
		}else{
			this->ctx.tail->next = tmp;
			tmp->prev = this->ctx.tail;
			this->ctx.tail=tmp;
		}
		addr = tmp->curraddr;	
		tmp->curraddr += size;
		tmp->usedSize -= size;
		this->ctx.allocated += sysTemMemPageSize;
		return addr;
	}
	char * _large = NULL;
	try 
	{
		_large = new char[size];
	}catch(std::bad_alloc){
		fprintf(stderr, "[ ERROR ] NEW MEM OCCUR ERROR IN FUNCTION:%s LINE:%d\n", __func__, __LINE__);
		return NULL;
	}
	addr = (void *)_large;
	if ( ctx.queue.count > 0 ){
		node = ctx.queue.queueHead;
		ctx.queue.queueHead = ctx.queue.queueHead->next;
		ctx.queue.count--;
	}else{
	    node = new struct Node_t;
	}
	INIT_NODE(node);
	node->addr = addr;
	node->size = size;
	if(!ctx.largeMem[size]){
		ctx.largeMem[size] = node;
	}else{
		struct Node_t *temp = ctx.largeMem[size];
		node->next = temp;
		ctx.largeMem[size] = node;
	}
	this->ctx.allocated += size;
	return addr;
}



/**
 * @brief: 
 * @author:
 * @para:
 * @return value:
 */
int MemPool::freeMemaddr(void *addr, int size ){
	assert( addr != NULL && size > 0);
	struct Node_t * node = NULL;
	if ( ctx.queue.count > 0 ){
		node = ctx.queue.queueHead;
		ctx.queue.queueHead = ctx.queue.queueHead->next;
		ctx.queue.count--;
	}else{
		node = new struct Node_t; 
	}
	INIT_NODE(node);
	node->addr = addr;
	node->size = size;
	if(!ctx.freeMem[size]){
		ctx.freeMem[size] = node;
	}else{
		struct Node_t *temp = ctx.freeMem[size];
		node->next = temp;
		ctx.freeMem[size] = node;
	}
	return RET::SUCCESS;
}


